/*
 *  Medieval Melee
 *  Copyright (C) 2009 Ben Foote
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Uzebox is a reserved trade mark
*/

#include "logic.h"

// Internal function prototypes
unsigned char LGCi_CheckRight(PLAYFIELD_TYPE tPlayfield, unsigned char x, unsigned char y, unsigned char blocktype);
unsigned char LGCi_CheckDown(PLAYFIELD_TYPE tPlayfield, unsigned char x, unsigned char y, unsigned char blocktype);
unsigned char LGCi_RowContains(PLAYFIELD_TYPE *tPlayfield, unsigned char ucRow, unsigned char ucType);
bool          LGCi_RowFull(PLAYFIELD_TYPE *tPlayfield, unsigned char ucRow);

// Initialize a playfield based on the difficulty level.
void LGC_InitializePlayfield(PLAYFIELD_TYPE *tPlayfield, unsigned char difficulty)
{
  for(unsigned char x = 0;x < 6;x++)
  {
    for(unsigned char y = 0;y < 12;y++)
    {
      if(y > (12 - difficulty))
        tPlayfield->tField[x][y].ucBlock = rand()%6;
      else
        tPlayfield->tField[x][y].ucBlock = 0;
        
      tPlayfield->tField[x][y].bMatched = false;
    }
  }
}

// Check the playfield for matches, and if found, mark them, but don't delete them.
bool LGC_CheckForMatches(PLAYFIELD_TYPE *tPlayfield)
{
  unsigned char x, y, i, ucHMatches, ucVMatches;
  bool bMatch = false;
  
  for(x = 0;x < 6;x++)
  {
    for(y = 0;y < 12;y++)
    {
      if(tPlayfield->tField[x][y].ucBlock != 0)
      {

        ucHMatches = LGCi_CheckRight(*tPlayfield, x,y,tPlayfield->tField[x][y].ucBlock);
        ucVMatches = LGCi_CheckDown(*tPlayfield, x,y,tPlayfield->tField[x][y].ucBlock);
        
        if(ucHMatches >= 2)
        {
          for(i = x;i <= (x + ucHMatches);i++)
          {
            tPlayfield->tField[i][y].bMatched = true;
          }
          ucHMatches = 0;
          bMatch = true;
        }
          
        if(ucVMatches >= 2)
        {
          for(i = y;i <= (y + ucVMatches);i++)
          {
            tPlayfield->tField[x][i].bMatched = true;         
          }
          ucVMatches = 0;
          bMatch = true;
        }
      }
    }    
  }
  
  return bMatch;
}


// Remove all the blocks that are matched in the playfield.
void LGC_RemoveMatches(PLAYFIELD_TYPE *tPlayfield)
{
    unsigned char x, y;
    
    for(x = 0;x < 6;x++)
    {
        for(y = 0;y < 12;y++)
        {
            if(tPlayfield->tField[x][y].bMatched == true)
                tPlayfield->tField[x][y].ucBlock = 0;
        }
    }
}

// If the blocks aren't stacked according to gravity, move the floating blocks down.
// This is an ugly triply nested loop that has only one optimization; if no moves are made
// in one pass, then bail out of the third loop. FIXME to not use a triply nested loop.
bool LGC_GravityCheck(PLAYFIELD_TYPE *tPlayfield)
{
  bool bMoved = false;
  unsigned char x, y, i;
  
  for(i = 0;i < 12;i++)
  {
    for(x = 0;x < 6;x++)
    {
      for(y = 0;y < 11;y++)
      {
        if((tPlayfield->tField[x][y].ucBlock != 0) && (tPlayfield->tField[x][y+1].ucBlock == 0))
        {
          tPlayfield->tField[x][y+1].ucBlock  = tPlayfield->tField[x][y].ucBlock;
          tPlayfield->tField[x][y+1].bMatched = tPlayfield->tField[x][y].bMatched;
          tPlayfield->tField[x][y].ucBlock  = 0;
          tPlayfield->tField[x][y].bMatched = false;
          bMoved = true;
        }
      }
    }
    
    if(bMoved == false)
      break;
  }
  
  return bMoved;
}

// Recursive function that checks blocks to the right of the current
// block for matches. Returns the total # of matches found.
unsigned char LGCi_CheckRight(PLAYFIELD_TYPE tPlayfield, unsigned char x, unsigned char y, unsigned char blocktype)
{
  if((x < 5) && (tPlayfield.tField[x+1][y].ucBlock == blocktype))
    return LGCi_CheckRight(tPlayfield, x+1,y,blocktype) + 1;
  else
    return 0;
}


// Recursive function that checks blocks below the current
// block for matches. Returns the total # of matches found.
unsigned char LGCi_CheckDown(PLAYFIELD_TYPE tPlayfield, unsigned char x, unsigned char y, unsigned char blocktype)
{
  if((y < 11) && (tPlayfield.tField[x][y+1].ucBlock == blocktype))
    return LGCi_CheckDown(tPlayfield, x, y+1, blocktype) + 1;
  else
    return 0;
}

// Swap blocks in playfield[x][y] and playfield[x+1][y].
void LGC_SwapBlock(PLAYFIELD_TYPE *tPlayfield, unsigned char x, unsigned char  y)
{
  unsigned char ucTemp = 0;
  bool          bMatch = false;
  
  ucTemp = tPlayfield->tField[x][y].ucBlock;
  bMatch = tPlayfield->tField[x][y].bMatched;
  
  tPlayfield->tField[x][y].ucBlock   = tPlayfield->tField[x+1][y].ucBlock;
  tPlayfield->tField[x][y].bMatched  = tPlayfield->tField[x+1][y].bMatched;
  
  tPlayfield->tField[x+1][y].ucBlock   = ucTemp;
  tPlayfield->tField[x+1][y].bMatched  = bMatch;
}


// Add a row to the bottom of the playing field. Return false
// if the playfield is full and we can't add a row.
bool LGC_AddRow(PLAYFIELD_TYPE *tPlayfield)
{
  bool bFull = false;
  unsigned char x, y;
  
  // Check to see if we have room at the top.
  for(x = 0;x < 6;x++)
  {
    if(tPlayfield->tField[x][0].ucBlock != 0)
    {
      bFull = true;
    }
  }
  
  if(bFull != true)
  {
    for(x = 0;x < 6;x++)
    {
      for(y = 1;y < 12;y++)
      {
        tPlayfield->tField[x][y-1].ucBlock  = tPlayfield->tField[x][y].ucBlock;
        tPlayfield->tField[x][y-1].bMatched = tPlayfield->tField[x][y].bMatched;
      }
    }
    
    for(x = 0;x < 6;x++)
    {
      tPlayfield->tField[x][11].ucBlock = 1 + rand()%6;
      tPlayfield->tField[x][11].bMatched = false;
    }
    
    return true;
  }
  else
  {
    return false;
  }  
}



